package cn.itcast.netty.c2;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.codec.string.StringDecoder;
import io.netty.handler.logging.LoggingHandler;

/**
 * netty是网络层中的王 相当于javaee中的spring
 * netty是基于nio的 也是基于Nio中的那种selector的多路复用的方式 根据事件来触发
 * 很多框架都有用netty 像zookeeper dubbo等
 * netty服务端入门 客户端发送数据 服务端接收
 * netty是用多线程的方式来实现异步的 其实就可以理解为多线程版本的多路复用 一个selector可以多路复用多个客户端线程
 * 然后针对客户端的连接事件 跟 读写事件又是分开处理的, 这个selector下的管理的 连接事件 跟 读写时间 他们自己去阻塞
 * 那么我们搞多几个selector不是更好？ netty就是这样的实现方式
 */
public class HelloServer {
    public static void main(String[] args) {
        // 1. 服务端启动器，负责组装 netty 组件，启动服务器
        new ServerBootstrap()
            // 2. eventloop是事件循环对象，group组 事件循环对象组
            // 这里其实就相当于 之前多线程版的 boss 跟 worker 理解:我们把boss跟worker这两个组注册进来了
            // 因为netty也是基于NIO那种方式 像selector调度那样的 所以也得添加类似boss worker那种组件进来
            // boss自然就是处理可连接事件的 worker自然就是处理可读可写事件的 所以下面的那些Handler等肯定就是由这个来调用的啦
            // EventLoop就可以理解为调用的工人 且在只有真正提交任务的时候才给你创建线程
            .group(new NioEventLoopGroup())
            // 3. 选择ServerSocket的实现
            .channel(NioServerSocketChannel.class) //支持 OIO(BIO)
            // 4. boss 负责处理连接 worker(child) 负责处理读写，这里决定了 worker(child) 能执行哪些操作（handler）
            .childHandler(//这里是启动的一个新的线程去做的
                    // 5. channel 代表和客户端进行数据读写的通道 Initializer 初始化，负责添加别的 handler
                new ChannelInitializer<NioSocketChannel>() {
                    //下面这个initChannel方法只有在accept()方法发生的时候才会被调用 (客户端建立连接的时候) 这里只是先装载进去 相当于给eventLoop发装备的
                    //accept这个方法是netty帮我们处理的只是accept的处理逻辑会去调用initChannel()
                    //即就是我们自己的处理逻辑来处理
                    //所以当服务器端产生accept()事件的时候 就调用下面的initChannel()去处理 然后里面的Handler就去处理对应责任的事情
                    //谁会调用的呢？ 其实就是EventLoopGroup中的eventLoop对象 一个eventLoop对象是一个线程
                @Override
                protected void initChannel(NioSocketChannel ch) throws Exception { //handler是按照编写顺序依次往下执行的
                    // 6. 添加具体 handler  handler可以对数据或者啥的进行处理
//                    ch.pipeline().addLast(new LoggingHandler());
                    ch.pipeline().addLast(new StringDecoder()); //这里是个解码的handler 负责把字节数据(ByteBuf)转换为字符串
                    ch.pipeline().addLast(new ChannelInboundHandlerAdapter() { // 自定义 handler
                        @Override // 自定义handler负责处理读事件
                        public void channelRead(ChannelHandlerContext ctx,Object msg) throws Exception {
                            System.out.println(msg); // 打印上一步转换好的字符串
                            //自定义的handler如果要消息往下传递记得自己编写 ctx.fireChannelRead(msg);代码 不然消息传递不下去
                        }
                    });
                }
            })
            // 7. 绑定服务器监听端口
            .bind(8080);
    }
}
